<template>
  <div :class="{ 'cursor-not-allowed': disabled }">
    <div
      :class="{
        horizontal: direction === 'horizontal',
        'ant-upload-disabled': disabled,
        'pointer-events-none': disabled,
      }"
      style="width: 100%"
    >
      <template v-if="showBtn && direction !== 'horizontal' && dragger">
        <UploadDragger
          :="$attrs"
          :disabled="disabled"
          :showUploadList="false"
          :customRequest="uploadApi"
          :accept="acceptStr"
          :multiple="multiple"
          :maxCount="maxNumber"
          :beforeUpload="beforeUpload"
          class="upload-list-inline1"
          @change="change"
        >
          <div>
            <UploadOutlined />
            <div style="margin-top: 8px">{{ title }}</div>
          </div>
        </UploadDragger>
        <slot name="tips"></slot>
      </template>
      <template v-if="direction !== 'horizontal' && !dragger">
        <Upload
          :="$attrs"
          :disabled="disabled"
          :showUploadList="false"
          :customRequest="uploadApi"
          :accept="acceptStr"
          :multiple="multiple"
          :maxCount="maxNumber"
          :beforeUpload="beforeUpload"
          class="upload-list-inline1"
          @change="change"
        >
          <slot name="upload-icon">
            <a-button type="primary" ghost>{{ title }}</a-button>
          </slot>
        </Upload>
        <slot name="tips"></slot>
      </template>
      <FilePreview
        :dragger="dragger"
        :disabled="disabled"
        :show-file-name="showFileName"
        @remove="handleRemove"
        :preview-list="fileList"
        :is-preview="isPreview"
        :is-download="isDownload"
        :valueField="valueField"
        :downloadField="downloadField"
        :labelField="labelField"
        :suffixField="suffixField"
        :maxNumber="maxNumber"
      >
        <UploadDragger
          :="$attrs"
          :disabled="disabled"
          :showUploadList="false"
          :customRequest="uploadApi"
          :accept="acceptStr"
          :multiple="multiple"
          :maxCount="maxNumber"
          :beforeUpload="beforeUpload"
          :class="[
            'upload-list-inline1',
            {
              'ant-upload-disabled': disabled,
              'pointer-events-none': disabled,
            },
          ]"
          @change="change"
          v-if="showBtn && direction === 'horizontal' && dragger"
        >
          <div>
            <UploadOutlined />
            <div style="margin-top: 8px">{{ title }}</div>
          </div>
        </UploadDragger>
        <div class="upload-btn-tips">
          <Upload
            :="$attrs"
            :disabled="disabled"
            :showUploadList="false"
            :customRequest="uploadApi"
            :accept="acceptStr"
            :multiple="multiple"
            :maxCount="maxNumber"
            :beforeUpload="beforeUpload"
            :class="[
              'upload-list-inline1',
              {
                'ant-upload-disabled': disabled,
                'pointer-events-none': disabled,
              },
            ]"
            @change="change"
            v-if="direction === 'horizontal' && !dragger"
          >
            <slot name="upload-icon">
              <a-button type="primary" ghost size="small">{{ title }}</a-button>
            </slot>
          </Upload>
          <slot name="tips"></slot>
        </div>
      </FilePreview>
    </div>
  </div>
</template>

<script setup lang="ts" name="HUpload">
  import { ref, computed, toRaw, unref, createVNode } from 'vue';
  import type { UploadProps, UploadFile } from 'ant-design-vue';
  import { BaseProps } from './props';
  import { is, isArray, isString } from '/@/utils/is';

  import { UploadOutlined, ExclamationCircleOutlined } from '@ant-design/icons-vue';
  import { Upload, Modal } from 'ant-design-vue';
  import { useMessage } from '/@/hooks/web/useMessage';
  import * as uploadCheck from '../hooks/uploadCheck';

  import FilePreview from './components/filePreview.vue';
  const UploadDragger = Upload.Dragger;

  // 具体参考api ant-design-vue upload组件
  const props = defineProps(BaseProps);

  const uploadFileList = ref<any>([]);

  const emits = defineEmits(['change', 'success', 'update:value', 'getData', 'delete']);

  const fileList = computed(() => {
    if (!isArray(unref(props.value))) return [];
    return props.value?.map((i) => {
      if (!i.status) {
        i.status = 'done';
      }
      return i;
    });
  });

  // const fileList = computed(() => props.value);

  const showBtn = computed(() => {
    return props.maxNumber
      ? fileList.value!.length < props.maxNumber && props.showUploadIcon
      : true;
  });

  const acceptStr = computed<string>(() => {
    let type = props.accept;
    let list: string[] = [];
    if (is(props.accept, 'Array')) {
      list = setAccpetPrefix(type as string[]);
      type = list.toString();
    }
    if (isString(type)) {
      list = setAccpetPrefix(type.split(','));
      type = list.toString();
    }
    return type as string;
  });

  // 给accpet 添加.前缀
  function setAccpetPrefix(type: string[]) {
    return type.map((i) => {
      if (i.indexOf('.') < 0) {
        i = `.${i}`;
      }
      return i;
    });
  }

  const { checkFileType, checkFileSize } = uploadCheck;

  const { createMessage } = useMessage();
  // 删除
  const handleRemove = async (fileObj) => {
    const list = fileList.value!.filter((i) => i.uid !== fileObj.uid).map((i) => toRaw(i));

    props.isBackSuccessData
      ? (uploadFileList.value = filterDone(list))
      : (uploadFileList.value = list);

    if (props.delApi) {
      // 调用接口删除
      Modal.confirm({
        title: () => '确定将该文件从服务器中删除吗？',
        icon: () => createVNode(ExclamationCircleOutlined),
        content: () => createVNode('div', { style: 'color:red;' }, '请谨慎操作'),
        async onOk() {
          await props.delApi(fileObj);
          emits('update:value', list);
          emits('change', toRaw(unref(uploadFileList)), 'delete');
          emits('delete', toRaw(fileObj));
          emits('getData', dataSet(toRaw(unref(uploadFileList))));
        },
        onCancel() {
          console.log('取消');
        },
      });
    } else {
      emits('update:value', list);
      emits('change', toRaw(unref(uploadFileList)), 'delete');
      emits('delete', toRaw(fileObj));
      emits('getData', dataSet(toRaw(unref(uploadFileList))));
    }
  };
  // 接口上传
  const uploadApi = async (file) => {
    let params = {
      file: file.file,
      name: props.name,
      filename: props.filename,
      data: {
        ...(props.uploadParams || {}),
      },
    };

    const API = props.api;
    if (!API) return;
    console.log('开始上传');

    try {
      const ret = await API(params);
      const { code, data, msg } = ret;
      if (!code) {
        file.onSuccess();
        const fileItem = {
          ...data,
          uid: file.file.uid,
          _file: file,
          status: 'done',
          percent: 100,
        };
        fileList.value?.push(fileItem);

        const index = fileList.value?.findIndex(
          (i) => i.uid === file.file.uid && i.status === 'uploading',
        );

        if ((index as number) > -1) {
          fileList.value?.splice(index as number, 1);
        }
        const list = fileList.value?.map((i) => toRaw(i));

        // uploadFileList.value = filterDone(toRaw(unref(fileList)));
        props.isBackSuccessData
          ? (uploadFileList.value = filterDone(list))
          : (uploadFileList.value = list);

        emits('update:value', fileList.value);
        emits('change', toRaw(unref(uploadFileList)));
        // 返回经过处理的数据
        emits('getData', dataSet(toRaw(unref(uploadFileList))));
        emits('success', toRaw(unref(uploadFileList)));
      } else {
        file.onError();
        const index = fileList.value?.findIndex(
          (i) => i.uid === file.file.uid && (i.status === 'uploading' || i.status === 'error'),
        );
        if ((index as number) > -1) {
          fileList.value![index as number].status = 'error';
          emits('update:value', fileList.value);
        }

        throw { msg };
      }
    } catch (e: any) {
      // createMessage.error(e.msg || '系统错误');
      throw e;
    }
  };

  // 获取过滤成功的url
  const filterDone = (list) => {
    if (!isArray(list)) {
      return list;
    }
    return list.filter((i) => i.status === 'done' || !i.status);
  };

  // 返回数据处理
  const dataSet = (data: Array<any>): string => data.map((i) => i[props.valueField]).toString();

  // 上传拦截
  const beforeUpload: UploadProps['beforeUpload'] = (file: UploadFile, filelist) => {
    const { name, size } = file;
    if (!checkFileType(name, unref(acceptStr))) {
      createMessage.warning(`只允许上传${unref(acceptStr)}后缀文件！`);
      return false || Upload.LIST_IGNORE;
    }

    if (!checkFileSize(size as number, props.maxSize)) {
      createMessage.warning(`最大只能上传${props.maxSize}MB的文件`);
      return false || Upload.LIST_IGNORE;
    }

    const isLimit = filelist.length + fileList.value!.length > props.maxNumber;
    const index = filelist.findIndex((i) => i.uid === file.uid) + fileList.value!.length;

    if (isLimit && index === props.maxNumber) {
      createMessage.warning(`最多${props.title}的数量为${props.maxNumber}`);
      return false || Upload.LIST_IGNORE;
    }
  };

  const change = (info) => {
    const file = info.file;
    if (file.status === 'uploading') {
      file[props.valueField] = file.name;

      let list = fileList.value?.map((i) => toRaw(unref(i)));
      list!.push(file);
      emits('update:value', list);
      emits('change', list);
    }
  };
</script>

<style lang="less" scoped>
  :deep(.upload-list-inline1) {
    width: 80px !important;
    height: 80px !important;
    margin-bottom: 10px;
    margin-right: 16px;
  }

  .horizontal {
    display: flex;
    flex-direction: row-reverse;
    justify-content: flex-end;
  }

  .upload-btn-tips {
    position: relative;
    height: 78px;
    margin-top: 2px;
    max-width: calc(100% - 145px);
  }
</style>
